package com.han.hotelplat.comm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * 步进执行器
 * 好处：
 * 1，随时更好执行顺序
 *
 * 特别：
 * 1，执行无参数的，因为你在调用runNext()你不知道这一步是做什么的。
 * 2，流程性：- 当前步执行成功，就可以调用runNext();
 *           - 当前步执行失败，一般就排查问题，然后重新执行reRunCur();
 *           - 所以只有在当前步成功，才会调用runNext();
 * 3，单线程。
 *
 * Created by lkm on 17/7/21.
 */

public class FlowStepRuner {

//    private List<Runnable> runs;

    public Runnable [] runs;
    private Map<String,Integer> runLableIndex;
    protected FlowStepRuner(Runnable [] runs, Map<String,Integer> runLableIndex){
        this.runs=runs;
        this.runLableIndex=runLableIndex;
    }

    private int runCount=-1;

    /**
     * 重新执行"当前步"
     * @return true 当前有可执行的步
     */
    public boolean reRunCur(){
        return runStep(runCount);
    }

    /**
     * "当前步"执行成功，进入下一步
     * @return true 当前有可执行的步
     */
    public boolean runNext(){
        return runStep(runCount+1);
    }

    /**
     * 直接执行某一步
     * @param label
     * @return 当前有可执行的步
     */
    public boolean runStep(String label){
        Integer num=runLableIndex.get(label);
        if(num==null)return false;
        return runStep(num);
    }

    /**
     * 直接执行某一步
     * @param num
     * @return 当前有可执行的步
     */
    private boolean runStep(int num){

        if(num==runs.length)return false ;

        runCount=num;
        runs[runCount].run();
        return true;

    }

    /**
     * 重置步数，runNext()将会从头执行
     */
    public void resetStep(){
        runCount=-1;
    }

    /**
     * 执行到哪步了
     * @return -1就是还没执行任何。如，0 就是当前是在执行第一步
     */
    public int getRunStep(){
        return runCount;
    }

    /**
     * 当前执行的
     * @return
     */
    public String getRunStepLabel(){
        return getRunStepLabel(runCount);
    }
    public String getNextRunStepLabel(){
        return getRunStepLabel(runCount+1);
    }
    public String getRunStepLabel(int index){
        for (String k :runLableIndex.keySet()) {
            if(runLableIndex.get(k).equals(index))
            return k;
        }
        return null;
    }

    /**
     * 是否执行了所有步。
     * @return
     */
    public boolean isComplete(){
        return runCount==runs.length-1;
    }
    
    public int getSize() {
    		return runs.length;
    }

    public static class Build{

        private LinkedHashMap<String,Runnable> runMaps=new LinkedHashMap<String,Runnable>();

        /**
         * @param label 标记
         * @param run
         * @return
         */
        public Build addRun(String label,Runnable run){
            runMaps.put(label,run);
            return this;
        }

        /**
         * label：默认取run的hashCode做
         * @param run
         * @return
         */
        public Build addRun(Runnable run){
            return addRun(""+run.hashCode(),run);
        }
        public FlowStepRuner build(){
            List<Runnable> runs=new ArrayList<Runnable>(runMaps.values());
            Map<String,Integer> runLableIndex=new HashMap<String,Integer>();
            Set<String> keys=runMaps.keySet();
            int index=-1;
            for (String k:keys) {
                index++;
                runLableIndex.put(k,index);
            }
            return new FlowStepRuner(runs.toArray(new Runnable[runs.size()]),runLableIndex);
        }
    }

}
